// ==================== 几何计算工具 ====================
// 基础设施层工具模块
// 职责：提供几何计算和空间分析能力

/**
 * 几何计算工具类
 * 提供各种几何计算和空间分析功能
 */
export class Geometry {
  
  // ==================== 基础几何计算 ====================
  
  /**
   * 计算两点之间的距离
   * @param {number} x1 - 第一个点的X坐标
   * @param {number} y1 - 第一个点的Y坐标
   * @param {number} x2 - 第二个点的X坐标
   * @param {number} y2 - 第二个点的Y坐标
   * @returns {number} 两点之间的距离
   */
  static distance(x1, y1, x2, y2) {
    const dx = x2 - x1
    const dy = y2 - y1
    return Math.sqrt(dx * dx + dy * dy)
  }
  
  /**
   * 计算点到直线的距离
   * @param {number} px - 点的X坐标
   * @param {number} py - 点的Y坐标
   * @param {number} x1 - 直线起点X坐标
   * @param {number} y1 - 直线起点Y坐标
   * @param {number} x2 - 直线终点X坐标
   * @param {number} y2 - 直线终点Y坐标
   * @returns {number} 点到直线的距离
   */
  static pointToLineDistance(px, py, x1, y1, x2, y2) {
    const A = px - x1
    const B = py - y1
    const C = x2 - x1
    const D = y2 - y1
    
    const dot = A * C + B * D
    const lenSq = C * C + D * D
    
    if (lenSq === 0) {
      return Geometry.distance(px, py, x1, y1)
    }
    
    const param = dot / lenSq
    let xx, yy
    
    if (param < 0) {
      xx = x1
      yy = y1
    } else if (param > 1) {
      xx = x2
      yy = y2
    } else {
      xx = x1 + param * C
      yy = y1 + param * D
    }
    
    return Geometry.distance(px, py, xx, yy)
  }
  
  /**
   * 计算角度（弧度）
   * @param {number} x1 - 起点X坐标
   * @param {number} y1 - 起点Y坐标
   * @param {number} x2 - 终点X坐标
   * @param {number} y2 - 终点Y坐标
   * @returns {number} 角度（弧度）
   */
  static angle(x1, y1, x2, y2) {
    return Math.atan2(y2 - y1, x2 - x1)
  }
  
  /**
   * 弧度转角度
   * @param {number} radians - 弧度
   * @returns {number} 角度
   */
  static radiansToDegrees(radians) {
    return radians * (180 / Math.PI)
  }
  
  /**
   * 角度转弧度
   * @param {number} degrees - 角度
   * @returns {number} 弧度
   */
  static degreesToRadians(degrees) {
    return degrees * (Math.PI / 180)
  }
  
  // ==================== 矩形计算 ====================
  
  /**
   * 检查点是否在矩形内
   * @param {number} px - 点的X坐标
   * @param {number} py - 点的Y坐标
   * @param {number} rx - 矩形X坐标
   * @param {number} ry - 矩形Y坐标
   * @param {number} rw - 矩形宽度
   * @param {number} rh - 矩形高度
   * @returns {boolean} 点是否在矩形内
   */
  static pointInRect(px, py, rx, ry, rw, rh) {
    return px >= rx && px <= rx + rw && py >= ry && py <= ry + rh
  }
  
  /**
   * 检查两个矩形是否相交
   * @param {Object} rect1 - 第一个矩形 {x, y, width, height}
   * @param {Object} rect2 - 第二个矩形 {x, y, width, height}
   * @returns {boolean} 是否相交
   */
  static rectsIntersect(rect1, rect2) {
    return !(rect1.x > rect2.x + rect2.width ||
             rect1.x + rect1.width < rect2.x ||
             rect1.y > rect2.y + rect2.height ||
             rect1.y + rect1.height < rect2.y)
  }
  
  /**
   * 计算两个矩形的交集
   * @param {Object} rect1 - 第一个矩形 {x, y, width, height}
   * @param {Object} rect2 - 第二个矩形 {x, y, width, height}
   * @returns {Object|null} 交集矩形或null
   */
  static rectIntersection(rect1, rect2) {
    if (!Geometry.rectsIntersect(rect1, rect2)) {
      return null
    }
    
    const x = Math.max(rect1.x, rect2.x)
    const y = Math.max(rect1.y, rect2.y)
    const width = Math.min(rect1.x + rect1.width, rect2.x + rect2.width) - x
    const height = Math.min(rect1.y + rect1.height, rect2.y + rect2.height) - y
    
    return { x, y, width, height }
  }
  
  /**
   * 计算两个矩形的并集
   * @param {Object} rect1 - 第一个矩形 {x, y, width, height}
   * @param {Object} rect2 - 第二个矩形 {x, y, width, height}
   * @returns {Object} 并集矩形
   */
  static rectUnion(rect1, rect2) {
    const x = Math.min(rect1.x, rect2.x)
    const y = Math.min(rect1.y, rect2.y)
    const width = Math.max(rect1.x + rect1.width, rect2.x + rect2.width) - x
    const height = Math.max(rect1.y + rect1.height, rect2.y + rect2.height) - y
    
    return { x, y, width, height }
  }
  
  /**
   * 计算矩形的边界框
   * @param {Array} points - 点数组 [{x, y}, ...]
   * @returns {Object} 边界框 {x, y, width, height}
   */
  static boundingRect(points) {
    if (points.length === 0) {
      return { x: 0, y: 0, width: 0, height: 0 }
    }
    
    let minX = points[0].x
    let minY = points[0].y
    let maxX = points[0].x
    let maxY = points[0].y
    
    for (let i = 1; i < points.length; i++) {
      const point = points[i]
      minX = Math.min(minX, point.x)
      minY = Math.min(minY, point.y)
      maxX = Math.max(maxX, point.x)
      maxY = Math.max(maxY, point.y)
    }
    
    return {
      x: minX,
      y: minY,
      width: maxX - minX,
      height: maxY - minY
    }
  }
  
  // ==================== 圆形计算 ====================
  
  /**
   * 检查点是否在圆形内
   * @param {number} px - 点的X坐标
   * @param {number} py - 点的Y坐标
   * @param {number} cx - 圆心X坐标
   * @param {number} cy - 圆心Y坐标
   * @param {number} radius - 半径
   * @returns {boolean} 点是否在圆形内
   */
  static pointInCircle(px, py, cx, cy, radius) {
    const distance = Geometry.distance(px, py, cx, cy)
    return distance <= radius
  }
  
  /**
   * 检查两个圆形是否相交
   * @param {number} x1 - 第一个圆心X坐标
   * @param {number} y1 - 第一个圆心Y坐标
   * @param {number} r1 - 第一个圆半径
   * @param {number} x2 - 第二个圆心X坐标
   * @param {number} y2 - 第二个圆心Y坐标
   * @param {number} r2 - 第二个圆半径
   * @returns {boolean} 是否相交
   */
  static circlesIntersect(x1, y1, r1, x2, y2, r2) {
    const distance = Geometry.distance(x1, y1, x2, y2)
    return distance <= r1 + r2
  }
  
  // ==================== 多边形计算 ====================
  
  /**
   * 检查点是否在多边形内（射线法）
   * @param {number} px - 点的X坐标
   * @param {number} py - 点的Y坐标
   * @param {Array} polygon - 多边形顶点数组 [{x, y}, ...]
   * @returns {boolean} 点是否在多边形内
   */
  static pointInPolygon(px, py, polygon) {
    if (polygon.length < 3) {
      return false
    }
    
    let inside = false
    const n = polygon.length
    
    for (let i = 0, j = n - 1; i < n; j = i++) {
      const xi = polygon[i].x
      const yi = polygon[i].y
      const xj = polygon[j].x
      const yj = polygon[j].y
      
      if (((yi > py) !== (yj > py)) && (px < (xj - xi) * (py - yi) / (yj - yi) + xi)) {
        inside = !inside
      }
    }
    
    return inside
  }
  
  /**
   * 计算多边形面积
   * @param {Array} polygon - 多边形顶点数组 [{x, y}, ...]
   * @returns {number} 多边形面积
   */
  static polygonArea(polygon) {
    if (polygon.length < 3) {
      return 0
    }
    
    let area = 0
    const n = polygon.length
    
    for (let i = 0, j = n - 1; i < n; j = i++) {
      area += (polygon[j].x + polygon[i].x) * (polygon[j].y - polygon[i].y)
    }
    
    return Math.abs(area) / 2
  }
  
  /**
   * 计算多边形周长
   * @param {Array} polygon - 多边形顶点数组 [{x, y}, ...]
   * @returns {number} 多边形周长
   */
  static polygonPerimeter(polygon) {
    if (polygon.length < 2) {
      return 0
    }
    
    let perimeter = 0
    const n = polygon.length
    
    for (let i = 0; i < n; i++) {
      const j = (i + 1) % n
      perimeter += Geometry.distance(
        polygon[i].x, polygon[i].y,
        polygon[j].x, polygon[j].y
      )
    }
    
    return perimeter
  }
  
  // ==================== 变换计算 ====================
  
  /**
   * 旋转点
   * @param {number} x - 点的X坐标
   * @param {number} y - 点的Y坐标
   * @param {number} cx - 旋转中心X坐标
   * @param {number} cy - 旋转中心Y坐标
   * @param {number} angle - 旋转角度（弧度）
   * @returns {Object} 旋转后的点 {x, y}
   */
  static rotatePoint(x, y, cx, cy, angle) {
    const cos = Math.cos(angle)
    const sin = Math.sin(angle)
    const dx = x - cx
    const dy = y - cy
    
    return {
      x: cx + dx * cos - dy * sin,
      y: cy + dx * sin + dy * cos
    }
  }
  
  /**
   * 缩放点
   * @param {number} x - 点的X坐标
   * @param {number} y - 点的Y坐标
   * @param {number} cx - 缩放中心X坐标
   * @param {number} cy - 缩放中心Y坐标
   * @param {number} scaleX - X轴缩放比例
   * @param {number} scaleY - Y轴缩放比例
   * @returns {Object} 缩放后的点 {x, y}
   */
  static scalePoint(x, y, cx, cy, scaleX, scaleY) {
    return {
      x: cx + (x - cx) * scaleX,
      y: cy + (y - cy) * scaleY
    }
  }
  
  /**
   * 平移点
   * @param {number} x - 点的X坐标
   * @param {number} y - 点的Y坐标
   * @param {number} dx - X轴平移距离
   * @param {number} dy - Y轴平移距离
   * @returns {Object} 平移后的点 {x, y}
   */
  static translatePoint(x, y, dx, dy) {
    return {
      x: x + dx,
      y: y + dy
    }
  }
  
  // ==================== 碰撞检测 ====================
  
  /**
   * 检查两个对象是否碰撞
   * @param {Object} obj1 - 第一个对象 {x, y, width, height, type}
   * @param {Object} obj2 - 第二个对象 {x, y, width, height, type}
   * @returns {boolean} 是否碰撞
   */
  static checkCollision(obj1, obj2) {
    // 矩形碰撞检测
    if (obj1.type === 'rect' && obj2.type === 'rect') {
      return Geometry.rectsIntersect(obj1, obj2)
    }
    
    // 圆形碰撞检测
    if (obj1.type === 'circle' && obj2.type === 'circle') {
      const r1 = obj1.width / 2
      const r2 = obj2.width / 2
      return Geometry.circlesIntersect(
        obj1.x + r1, obj1.y + r1, r1,
        obj2.x + r2, obj2.y + r2, r2
      )
    }
    
    // 混合碰撞检测（矩形与圆形）
    if (obj1.type === 'rect' && obj2.type === 'circle') {
      return Geometry.rectCircleCollision(obj1, obj2)
    }
    
    if (obj1.type === 'circle' && obj2.type === 'rect') {
      return Geometry.rectCircleCollision(obj2, obj1)
    }
    
    return false
  }
  
  /**
   * 矩形与圆形碰撞检测
   * @param {Object} rect - 矩形对象 {x, y, width, height}
   * @param {Object} circle - 圆形对象 {x, y, width, height}
   * @returns {boolean} 是否碰撞
   */
  static rectCircleCollision(rect, circle) {
    const radius = circle.width / 2
    const cx = circle.x + radius
    const cy = circle.y + radius
    
    // 找到矩形上最近的点
    const closestX = Math.max(rect.x, Math.min(cx, rect.x + rect.width))
    const closestY = Math.max(rect.y, Math.min(cy, rect.y + rect.height))
    
    // 计算圆心到最近点的距离
    const distance = Geometry.distance(cx, cy, closestX, closestY)
    
    return distance <= radius
  }
  
  // ==================== 工具方法 ====================
  
  /**
   * 限制值在指定范围内
   * @param {number} value - 要限制的值
   * @param {number} min - 最小值
   * @param {number} max - 最大值
   * @returns {number} 限制后的值
   */
  static clamp(value, min, max) {
    return Math.min(Math.max(value, min), max)
  }
  
  /**
   * 线性插值
   * @param {number} a - 起始值
   * @param {number} b - 结束值
   * @param {number} t - 插值因子 (0-1)
   * @returns {number} 插值结果
   */
  static lerp(a, b, t) {
    return a + (b - a) * t
  }
  
  /**
   * 计算两点之间的中点
   * @param {number} x1 - 第一个点的X坐标
   * @param {number} y1 - 第一个点的Y坐标
   * @param {number} x2 - 第二个点的X坐标
   * @param {number} y2 - 第二个点的Y坐标
   * @returns {Object} 中点 {x, y}
   */
  static midpoint(x1, y1, x2, y2) {
    return {
      x: (x1 + x2) / 2,
      y: (y1 + y2) / 2
    }
  }
  
  /**
   * 计算点到线段的最短距离
   * @param {number} px - 点的X坐标
   * @param {number} py - 点的Y坐标
   * @param {number} x1 - 线段起点X坐标
   * @param {number} y1 - 线段起点Y坐标
   * @param {number} x2 - 线段终点X坐标
   * @param {number} y2 - 线段终点Y坐标
   * @returns {number} 最短距离
   */
  static pointToSegmentDistance(px, py, x1, y1, x2, y2) {
    const A = px - x1
    const B = py - y1
    const C = x2 - x1
    const D = y2 - y1
    
    const dot = A * C + B * D
    const lenSq = C * C + D * D
    
    if (lenSq === 0) {
      return Geometry.distance(px, py, x1, y1)
    }
    
    const param = Geometry.clamp(dot / lenSq, 0, 1)
    const xx = x1 + param * C
    const yy = y1 + param * D
    
    return Geometry.distance(px, py, xx, yy)
  }
}
